<script setup lang="ts">
import { fetchLuaFiles, saveLuaFile, fetchDriverUsage } from '@/service/api/deviceType'
import NovaIcon from '@/components/common/NovaIcon.vue'
import { NAlert, NButton, NModal, NSpace, NSpin, NTag } from 'naive-ui'
import CodeEditor from '@/components/common/CodeEditor.vue'

defineOptions({ name: 'LuaEditorModal' })

interface Props {
  visible: boolean
  driver: string
}

const props = withDefaults(defineProps<Props>(), {
  visible: false,
  driver: '',
})

interface Emits {
  (e: 'update:visible', visible: boolean): void
}

const emit = defineEmits<Emits>()

// 主要函数类型定义
interface LuaFunction {
  name: string
  label: string
  description: string
  required: boolean
  template: string
}

// 定义 Lua 插件的主要函数
const luaFunctions: LuaFunction[] = [
  {
    name: 'DetectProtocol',
    label: '协议检测',
    description: '判断数据是否为该协议，返回 true 或 false',
    required: true,
    template: `-- 协议检测函数（必需）
-- 参数：data (数据数组), dataLen (数据长度)
-- 返回：true 或 false
function DetectProtocol(data, dataLen)
    if dataLen < 8 then
        return false
    end
    
    -- 检查协议特征（修改为你的协议特征）
    if data[1] == 0x68 then
        print("[协议] 协议检测通过")
        return true
    end
    
    return false
end`,
  },
  {
    name: 'ExtractDeviceAddress',
    label: '设备地址提取',
    description: '从数据中提取设备地址并返回字符串地址',
    required: true,
    template: `function ExtractDeviceAddress()
    return ""
end`,
  },
  {
    name: 'AnalysisRx',
    label: '数据解析',
    description: '解析接收到的数据并返回结构化结果',
    required: true,
    template: `-- 数据解析函数（必需）
-- 参数：sAddr (设备地址), rxBufCnt (数据长度)
-- 全局变量：rxBuf (数据数组)
-- 返回：{Status, Variable, FrameType, NeedResponse, Response}
function AnalysisRx(sAddr, rxBufCnt)
    if rxBufCnt < 8 then
        return {Status = "1", Variable = {}}
    end
    
    local variables = {}
    
    -- 解析数据（示例）
    local value1 = rxBuf[5] + rxBuf[6] * 256
    table.insert(variables, utils.AppendVariable(0, "value1", "数值1", "double", value1, ""))
    
    return {
        Status = "0",
        Variable = variables,
        FrameType = "data",
        NeedResponse = false,
        Response = {}
    }
end`,
  },
  {
    name: 'GenerateGetRealVariables',
    label: '生成采集命令',
    description: '生成主动采集设备数据的命令（可选）',
    required: false,
    template: `-- 生成采集命令函数（可选）
-- 参数：address (设备地址), step (步骤)
-- 返回：{Status, Variable}
function GenerateGetRealVariables(address, step)
    local cmd = {0x68, 0x10, 0x03, 0x00, 0x16}
    return {Status = "0", Variable = cmd}
end`,
  },
  {
    name: 'DeviceCustomCmd',
    label: '自定义命令',
    description: '处理自定义命令，如开关控制（可选）',
    required: false,
    template: `-- 自定义命令函数（可选）
-- 参数：sAddr (设备地址), cmdName (命令名), cmdParam (命令参数), step (步骤)
-- 返回：{Status, Variable}
function DeviceCustomCmd(sAddr, cmdName, cmdParam, step)
    if cmdName == "Control" then
        local cmd = {0x68, 0x10, 0x05, 0x01, 0x16}
        return {Status = "0", Variable = cmd}
    end
    
    return {Status = "1", Variable = {}}
end`,
  },
]

const files = ref<Record<string, string>>({})
const fileList = ref<string[]>([])
const currentFile = ref('')
const fullContent = ref('')
const functionPresence = ref<Record<string, boolean>>({})
const isSaving = ref(false)
const isLoading = ref(false)

// 本地的 visible 状态
const localVisible = computed({
  get: () => props.visible,
  set: (val) => emit('update:visible', val),
})

// 协议使用情况
const driverUsage = ref<{ deviceTypes: string[], count: number }>({
  deviceTypes: [],
  count: 0,
})

watch(
  [() => props.visible, () => props.driver],
  ([visible, driver]) => {
    if (visible && driver) {
      loadFiles(driver)
      loadDriverUsage(driver)
    }
  },
  { immediate: true },
)

// 检测并提取函数（供侧边栏检测使用）
function extractFunctions(content: string) {
  const functions: Record<string, string> = {}

  // 简单词法扫描，跳过字符串与注释，匹配 function 开始到其对应 end
  function findFunctionBody(name: string): string | null {
    let i = 0
    const n = content.length
    let depth = 0
    let inFunc = false
    let startPos = -1

    const isAlphaNum = (ch: string) => /[A-Za-z0-9_]/.test(ch)
    const atWord = (word: string) => content.startsWith(word, i) &&
      (!isAlphaNum(content[i - 1] || '')) && (!isAlphaNum(content[i + word.length] || ''))

    while (i < n) {
      const ch = content[i]

      // 跳过单行注释 --
      if (content.startsWith('--', i)) {
        // 长注释 --[[ ... ]]
        if (content.startsWith('--[[', i)) {
          i += 4
          const endLong = content.indexOf(']]', i)
          i = endLong === -1 ? n : endLong + 2
          continue
        }
        // 普通行注释
        const nl = content.indexOf('\n', i)
        i = nl === -1 ? n : nl + 1
        continue
      }

      // 跳过长字符串 [[...]] 或 [=*[...]=*]
      if (ch === '[') {
        // 匹配可变等号长字符串开头
        const longStrOpen = content.slice(i).match(/^\[(=*)\[/)
        if (longStrOpen) {
          const eqs = longStrOpen[1]
          i += 2 + eqs.length
          const closePattern = new RegExp(`\\]${eqs}\\]`)
          const rest = content.slice(i)
          const m = rest.match(closePattern)
          if (m) {
            // 跳过到匹配结束符之后
            const idx = rest.search(closePattern)
            i += idx + 2 + eqs.length
          } else {
            i = n
          }
          continue
        }
      }

      // 跳过字符串 '...' 或 "..."
      if (ch === '"' || ch === '\'') {
        const quote = ch
        i++
        while (i < n) {
          if (content[i] === '\\') { i += 2; continue }
          if (content[i] === quote) { i++; break }
          i++
        }
        continue
      }

      // 进入 function（精确匹配单词边界），并确认目标函数名
      if (atWord('function')) {
        // 预读函数名，支持 a.b:c 形式，取最后的片段
        let look = i + 'function'.length
        // 跳过空白
        while (look < n && /\s/.test(content[look])) look++
        // 收集标识符/限定符
        let nameStart = look
        while (look < n && /[A-Za-z0-9_\.:]/.test(content[look])) look++
        const rawName = content.slice(nameStart, look)
        const lastSeg = rawName.split(/[\.:]/).pop() || ''
        if (lastSeg === name) {
          // 确认是目标函数，从此处开始计深度
          startPos = i
          i += 'function'.length
          depth = 1
          inFunc = true
          continue
        } else {
          // 不是目标函数
          if (inFunc) {
            // 目标函数体内出现嵌套 function，需要计入深度
            depth++
          }
          i += 'function'.length
          continue
        }
      }

      // 其他会以 end 结束的块，增加深度，避免把中间的 if/end 识别为函数结尾
      if (atWord('if') || atWord('for') || atWord('while') || atWord('do')) {
        if (inFunc) depth++
        i += (content.startsWith('while', i) ? 5 : content.startsWith('for', i) ? 3 : content.startsWith('if', i) ? 2 : 2)
        continue
      }

      // repeat ... until 结构
      if (atWord('repeat')) {
        if (inFunc) depth++
        i += 'repeat'.length
        continue
      }

      // 'elseif' 不改变深度，直接跳过单词
      if (atWord('elseif')) { i += 'elseif'.length; continue }

      // 匹配 end（精确匹配单词边界）
      if (atWord('end')) {
        if (inFunc) {
          depth--
          i += 3
          if (depth === 0) {
            // 包含末尾 end
            return startPos >= 0 ? content.substring(startPos, i).trim() : null
          }
          continue
        }
      }

      // repeat 的结束关键字是 until，遇到 until 也要 depth--
      if (atWord('until')) {
        if (inFunc) {
          depth--
          i += 'until'.length
          if (depth === 0) {
            return startPos >= 0 ? content.substring(startPos, i).trim() : null
          }
          continue
        }
      }

      i++
    }

    return null
  }

  luaFunctions.forEach((func) => {
    const body = findFunctionBody(func.name)
    if (body) functions[func.name] = body
  })

  return functions
}

function detectFunctionPresence(content: string) {
  // 先移除注释与字符串，避免误报/漏报
  const n = content.length
  let i = 0
  let clean = ''
  while (i < n) {
    const ch = content[i]
    // 行注释
    if (content.startsWith('--', i)) {
      if (content.startsWith('--[[', i)) {
        i += 4
        const end = content.indexOf(']]', i)
        i = end === -1 ? n : end + 2
        continue
      }
      const nl = content.indexOf('\n', i)
      i = nl === -1 ? n : nl + 1
      clean += '\n'
      continue
    }
    // 长字符串 [=*[ ... ]=*]
    if (ch === '[') {
      const m = content.slice(i).match(/^\[(=*)\[/)
      if (m) {
        const eqs = m[1]
        i += 2 + eqs.length
        const close = content.slice(i).search(new RegExp(`\]${eqs}\]`))
        if (close === -1) { i = n } else { i += close + 2 + eqs.length }
        clean += ' '
        continue
      }
    }
    // 普通字符串
    if (ch === '"' || ch === '\'') {
      const quote = ch
      i++
      while (i < n) {
        if (content[i] === '\\') { i += 2; continue }
        if (content[i] === quote) { i++; break }
        i++
      }
      clean += ' '
      continue
    }
    clean += ch
    i++
  }

  const map: Record<string, boolean> = {}
  luaFunctions.forEach((f) => {
    const name = f.name.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&')
    const re = new RegExp(`\\b(?:local\\s+)?function\\s+[\\w\\.]*:?${name}\\s*\\(`)
    map[f.name] = re.test(clean)
  })
  return map
}

// 将各个函数组合成完整文件
// 组合函数已废弃，现改为直接编辑完整文件

async function loadFiles(driver: string) {
  if (!driver)
    return

  isLoading.value = true
  try {
    const { isSuccess, data } = await fetchLuaFiles(driver)
    console.log('API返回:', { isSuccess, data })
    
    if (isSuccess && data) {
      files.value = data
      fileList.value = Object.keys(data).sort()
      console.log('文件列表:', fileList.value)
      
      // 默认选择主 Lua 文件
      const mainFile = `${driver}.lua`
      if (fileList.value.includes(mainFile)) {
        currentFile.value = mainFile
        fullContent.value = data[mainFile] || ''
        functionPresence.value = detectFunctionPresence(fullContent.value)
      }
      else if (fileList.value.length > 0) {
        currentFile.value = fileList.value[0]
        fullContent.value = data[fileList.value[0]] || ''
        functionPresence.value = detectFunctionPresence(fullContent.value)
      }
    }
  }
  catch (e: any) {
    console.error('加载文件失败:', e)
    window.$message.error(e.message || '加载文件失败')
  }
  finally {
    isLoading.value = false
  }
}

async function loadDriverUsage(driver: string) {
  try {
    const { isSuccess, data } = await fetchDriverUsage(driver)
    if (isSuccess && data) {
      driverUsage.value = data
    }
  }
  catch (e: any) {
    console.error('加载协议使用情况失败:', e)
  }
}

async function handleSave() {
  if (!currentFile.value || !props.driver) {
    window.$message.warning('请选择要保存的文件')
    return
  }

  isSaving.value = true
  try {
    const { isSuccess } = await saveLuaFile(props.driver, currentFile.value, fullContent.value)
    if (isSuccess) {
      window.$message.success('保存成功')
      // 更新本地缓存
      files.value[currentFile.value] = fullContent.value
    }
  }
  catch (e: any) {
    window.$message.error(e.message || '保存失败')
  }
  finally {
    isSaving.value = false
  }
}

function closeModal() {
  console.log('关闭模态框')
  emit('update:visible', false)
}

watch(fullContent, (val) => {
  functionPresence.value = detectFunctionPresence(val || '')
})
</script>

<template>
  <NModal
    v-model:show="localVisible"
    :title="`编辑协议：${driver}`"
    preset="card"
    class="w-90vw h-85vh"
  >
    <NSpin :show="isLoading">
      <div class="h-full flex flex-col gap-12px" style="height: calc(85vh - 150px);">
        <!-- 顶部工具栏 -->
        <div class="flex items-center justify-between">
          <div class="flex items-center gap-12px">
            <NovaIcon icon="vscode-icons:file-type-lua" :size="24" />
            <span class="text-16px font-bold">{{ currentFile }}</span>
          </div>
        </div>

        <!-- 协议使用提示（压缩为两行） -->
        <NAlert
          v-if="driverUsage.count > 0"
          class="usage-alert"
          type="warning"
          size="small"
          :bordered="false"
          :style="{ padding: '6px 10px', lineHeight: '1.3' }"
        >
          <template #header>
            ⚠️ 使用情况
          </template>
          此协议被 <strong>{{ driverUsage.count }}</strong> 个设备类型使用：
          <NTag
            v-for="dt in driverUsage.deviceTypes"
            :key="dt"
            size="tiny"
            class="ml-4px"
          >
            {{ dt }}
          </NTag>
        </NAlert>

        <!-- 编辑器 + 侧边函数检测 -->
        <div class="flex-1 min-h-0 flex gap-12px">
          <div class="editor-wrapper flex-1">
            <CodeEditor
              v-model:modelValue="fullContent"
              language="lua"
              theme="dark"
              placeholder="编辑 Lua 插件完整文件"
            />
          </div>

          <div class="sidebar w-260px">
            <div class="sidebar-card">
              <div class="sidebar-title">函数检测</div>
              <div class="sidebar-sub">必需 {{ luaFunctions.filter(f=>f.required).length }} · 可选 {{ luaFunctions.filter(f=>!f.required).length }}</div>
              <div class="func-list">
                <div v-for="func in luaFunctions" :key="func.name" class="func-item">
                  <div class="func-main">
                    <span class="func-name">{{ func.name }}</span>
                    <NTag v-if="func.required" size="tiny" type="error">必需</NTag>
                    <NTag v-else size="tiny">可选</NTag>
                  </div>
                  <div class="func-status">
                    <NTag :type="functionPresence[func.name] ? 'success' : 'warning'" size="tiny">
                      {{ functionPresence[func.name] ? '已检测到' : '缺失' }}
                    </NTag>
                  </div>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
    </NSpin>

    <template #footer>
      <NSpace justify="space-between">
        <NSpace>
          <NTag size="small" type="success">
            <NovaIcon icon="icon-park-outline:check-one" class="mr-4px" />
            必需 {{ luaFunctions.filter(f => f.required).length }} · 可选 {{ luaFunctions.filter(f => !f.required).length }}
          </NTag>
        </NSpace>
        <NSpace>
          <NButton @click="closeModal">
            关闭
          </NButton>
          <NButton
            type="primary"
            :loading="isSaving"
            @click="handleSave"
          >
            <template #icon>
              <NovaIcon icon="icon-park-outline:save" />
            </template>
            保存
          </NButton>
        </NSpace>
      </NSpace>
    </template>
  </NModal>
</template>

<style scoped>
.font-mono :deep(textarea) {
  font-family: 'Consolas', 'Monaco', 'Courier New', monospace !important;
  tab-size: 2;
}

.content-body {
  padding-bottom: 8px;
  min-height: 0;
}

.editor-wrapper {
  min-height: 0;
  border: 1px solid #e0e0e0;
  border-radius: 6px;
  overflow: hidden;
}

.editor-wrapper :deep(.code-editor) {
  height: 100%;
  border: none;
  border-radius: 0;
}

.editor-wrapper :deep(.cm-editor) {
  height: 100%;
}
</style>

